#include "main.h"

int 
cilk_main(int argc, char *argv[])
{
  if (argc != 4) {
    goto badinput;
  }

  if (!strcmp(argv[1], "naive")) {
    return run_lcs(argv[2], argv[3], NAIVE);
  }
  else if (!strcmp(argv[1], "linear")) {
    return run_lcs(argv[2], argv[3], LINEAR);
  }
  else if (!strcmp(argv[1], "similar")) {
    return run_lcs(argv[2], argv[3], SIMILAR);
  }

 badinput:
  fprintf (stderr, "Usage: main <lcs_algorithm> <path1> <path2>\n" );
  fprintf (stderr, "Algorithms supported: naive, linear\n" );
  exit(1);
}

int
run_lcs(char *path1, char *path2, int alg)
{
  FILE *fp1, *fp2, *fp3; // FDs
  uint32_t sz1, sz2; // File sizes
  char *s1, *s2; // Byte strings
  char *lcs; // LCS
  int32_t n = -1; // LCS length
  struct timeval tv_start, tv_end, tv_taken;

  // Open both pathnames
  fp1 = fopen(path1, "r");
  fp2 = fopen(path2, "r");

  if (!fp1 || !fp2) {
    fprintf(stderr, "Failed to open one (or both) pathnames!\n");
    return -1;
  }

  // Get length of byte strings
  fseek(fp1, 0L, SEEK_END);
  sz1 = ftell(fp1);
  fseek(fp1, 0L, SEEK_SET);
  fseek(fp2, 0L, SEEK_END);
  sz2 = ftell(fp2);
  fseek(fp2, 0L, SEEK_SET);

  // Allocate memory for byte strings
  s1 = (char *) malloc(sizeof(char) * sz1);
  s2 = (char *) malloc(sizeof(char) * sz2);

  if (!s1 || !s2) {
    fprintf(stderr, "Out of memory!\n");
    return -1;
  }

  // Read byte string 1
  if (fread(s1, 1, sz1, fp1) != sz1) {
    fprintf(stderr, "Failed to read file 1.\n");
    return -1;
  }

  // Read byte string 2
  if (fread(s2, 1, sz2, fp2) != sz2) {
    fprintf(stderr, "Failed to read file 2.\n");
    return -1;
  }

  gettimeofday(&tv_start, NULL);

  // Run LCS dp algorithm
  switch(alg) {
  case NAIVE:
    n = run_lcs_naive(s1, sz1, s2, sz2, &lcs);
    break;
  case LINEAR:
    n = run_lcs_linear(s1, sz1, s2, sz2, &lcs);
    break;
  case SIMILAR:
    n = run_lcs_similar(s1, sz1, s2, sz2, &lcs);
  }

  gettimeofday(&tv_end, NULL);
  timersub(&tv_end, &tv_start, &tv_taken);

  // Output result and write LCS to file
  if (n >= 0) {
    fprintf(stdout, "LCS length: %i\n", n);
    fprintf(stdout, "Time taken: %i.%is \n", (int)tv_taken.tv_sec, 
	    (int)tv_taken.tv_usec);

    fp3 = fopen("lcs.out", "w");
    if (!fp3) {
      fprintf(stderr, "Failed to create/open out file.\n");
      return -1;
    }

    if ((size_t) n != fwrite(lcs, 1, n, fp3)) {
      fprintf(stderr, "Failed to write LCS to out.\n");
      return -1;
    }

    free(lcs);
  }
  else {
    fprintf(stderr, "Computing LCS failed.\n");
    return -1;
  }

  free(s1);
  free(s2);

  return n;
}
